The present invention concerns data encryption and pertains particularly to a pipelined hardware implementation of a hashing algorithm.
The RSA Data Security, Inc. MD5 Message-Digest Algorithm uses four state registers a, b, c and d to store a digest of 128 bits. These state registers are initialized to a known value before data is hashed through the algorithm. There are 64 operations of hashing that take place in the algorithm. These operations are split into four rounds of 16 transformations. Each of the four blocks uses a base function called a transformation to rotate and combine the state registers based on the input data. The transform uses a base function register that combines the data along with a specific shift and combine strategy.
The RSA Data Security, Inc. MD5 Message-Digest Algorithm is set out in Table 1 below.
TABLE 1 ______________________________________ /* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm /* /* Copyright (C) 1991, RSA Data Security, Inc. All rights reserved. License to copy and use this software is granted provided that it is identified as the "RSA Data Security, Inc. MDS Message-Digest Algorithm" in all material mentioning or referencing this software or this function. License is also granted to make and use derivative works provided that such works are identified as "derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm" in all material mentioning or referencing the derived work. RSA Data Security, Inc. makes no representations concerning either the merchantability of this software or the suitability of this software for any particular purpose. It is provided "as is" without express or implied warranty of any kind. These notices must be retained in any copies of any part of this documentation and/or software. */ #include "global.h" #include "md5.h" /* Constants for MD5Transform routine. /* #define S11 7 #define S12 12 #define S13 17 #define S14 22 #define S21 5 #define S22 9 #define S23 14 #define S24 20 #define S31 4 #define S32 11 #define S33 16 #define S34 23 #define S41 6 #deflne S42 10 #define S43 15 #define S44 21 static void MD5Transform PROTO.sub.-- LIST ((UINT4 [4], unsigned char [64])); static void Encode PROTO.sub.-- LIST ((unsigned char *, UINT4 *, unsigned int)); static void Decode PROTO.sub.-- LIST ((UINT4 *, unsigned char *, unsigned int)); static void MD5.sub.-- memcpy PROTO.sub.-- LIST ((POINTER, POINTER, unsigned int)); static void MD5.sub.-- memset PROTO.sub.-- LIST ((POINTER, int, unsigned int)); static unsigned char PADDING[64] = { 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; /* F, G, H and I are basic MD5 functions. */ #define F(x, y, z) (((x) & (y)) .vertline. ((.about.x) & (z))) #define G(x, y, z) (((x) & (z)) .vertline. ((y) & (.about.z))) #define H(x, y, z) ((x) (y) (z)) #define I(x, y, z) ((y) ((x) .vertline. (.about.z))) /* ROTATE.sub.-- LEFT rotates x left n bits. */ #define ROTATE.sub.-- LEFT(x, n) (((x) &lt;&lt; (n)) .vertline. ((x) &gt;&gt; (32-(n)))) /* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. Rotation is separate from addition to prevent recomputation. */ #define FF(a, b, c, d, x, s, ac) { .backslash. (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); .backslash. (a) = ROTATE.sub.-- LEFT ((a), (s)); .backslash. (a) += (b); .backslash. } #define GG(a, b, c, d, x, s, ac) { .backslash. (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); .backslash. (a) = ROTATE.sub.-- LEFT ((a), (s)); .backslash. (a) += (b); .backslash. } #define HH(a, b, c, d, x, s, ac) { .backslash. (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); .backslash. (a) = ROTATE.sub.-- LEFT ((a), (s)); .backslash. (a) += (b); .backslash. } #define II(a, b, c, d, x, s, ac) { .backslash. (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); .backslash. (a) = ROTATE.sub.-- LEFT ((a), (s)); .backslash. (a) += (b); .backslash. } /* MD5 initialization. Begins an MD5 operation, writing a new context. */ void MD5Init (context) MD5.sub.-- CTX *context; /* context */ context-&gt;count[0] = context-&gt;count[1] = 0; /* Load magic initialization constants. */ context-&gt;state[0] = 0x67452301; context-&gt;state[1] = 0xefcdab89; context-&gt;state[2] = 0x98badcfe; context-&gt;state[3] = 0x10325476; } /* MD5 block update operation. Continues an MD5 message-digest operation, processing another message block, and updating the context. */ void MDSUpdate (context, input, inputLen) MD5.sub.-- CTX *context; /* context */ unsigned char *input; /* input block */ unsigned int inputLen; /* length of input block */ { unsigned int i, index, partLen; /* Compute number of bytes mod 64 */ index = (unsigned int)((context-&gt;count[0] &gt;&gt; 3) & 0x3F); /* Update number of bits */ if ((context-&gt;count[0] += ((UINT4)inputLen &lt;&lt; 3)) &lt; ((UINT4)inputLen &lt;&lt; 3)) context-&gt;count[1]++; context-&gt;count[1] += ((UINT4)inputLen &gt;&gt; 29); partLen = 64 - index; /* Transform as many times as possible. */ if (inputLen &gt;= partLen) { MD5.sub.-- memcpy ((POINTER)&context-&gt;buffer [index], (POINTER)input, partLen); MD5Transform (context-&gt;state, context-&gt;buffer); for (i = partLen; i + 63 &lt; inputLen; i += 64) MD5Transform (context-&gt;state, &input [i]); index = 0; } else i = 0; /* Buffer remaining input */ MD5.sub.-- memcpy ((POINTER)&context-&gt;buffer [index], (POINTER)&input [i], inputLen-i); } /* MD5 finalization. Ends an MDS message-digest operation, writing the the message digest and zeroizing the context. */ void MD5Final (digest, context) unsigned char digest[16]; /* message digest */ MD5.sub.-- CTX *context; /* context */ { unsigned char bits[8]; unsigned int index, padLen; /* Save number of bits */ Encode (bits, context-&gt;count, 8); /* Pad out to 56 mod 64. */ index = (unsigned int)((context-&gt;count[0] &gt;&gt; 3) & 0x3f); padLen = (index &lt; 56) ? (56 - index) : (120 - index); MD5Update (context, PADDING, padLen); /* Append length (before padding) */ MD5Update (context, bits, 8); /* Store state in digest */ Encode (digest, context-&gt;state, 16); /* Zeroize sensitive information. */ MDS.sub.-- memset ((POINTER)context, 0, sizeof (*context)); } /* MD5 basic transformation. Transforms state based on block. */ static void MD5Transform (state, block) UINT4 state[4]; unsigned char block[64]; { UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; Decode (x, block, 64); /* Round 1 */ FF ( a, b, c, d, x[0], S11, 0xd76aa478); /* 1 */ FF ( d, a, b, c, x[1], S12, 0xe8c7b756); /* 2 */ FF ( c, d, a, b, x[2], S13, 0x242070db); /* 3 */ FF ( b, c, d, a, x[3], S14, 0xc1bdceee); /* 4 */ FF ( a, b, c, d, x[4], S11, 0xf57c0faf); /* 5 */ FF ( d, a, b, c, x[5], S12, 0x4787c62a); /* 6 */ FF ( c, d, a, b, x[6], S13, 0xa8304613); /* 7 */ FF ( b, c, d, a, x[7], S14, 0xfd469501); /* 8 */ FF ( a, b, c, d, x[8], S11, 0x698098d8); /* 9 */ FF ( d, a, b, c, x[9], S12, 0x8b44f7af); /* 10 */ FF ( c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ FF ( b, c, d, a, x[11], S14, 0x89Scd7be); /* 12 */ FF ( a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ FF ( d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ FF ( c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ FF ( b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ /* Round 2 */ GG ( a, b, c, d, x[1], S21, 0xf61e2562); /* 17 */ GG ( d, a, b, c, x[6], S22, 0xc040b340); /* 18 */ GG ( c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ GG ( b, c, d, a, x[0], S24, 0xe9b6c7aa); /* 20 */ GG ( a, b, c, d, x[5], S21, 0xd62f105d); /* 21 */ GG ( d, a, b, c, x[10], S22, 0x2441453); /* 22 */ GG ( c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ GG ( b, c, d, a, x[4], S24, 0xe7d3fbc8); /* 24 */ GG ( a, b, c, d, x[9], S21, 0x21e1cde6); /* 25 */ GG ( d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ GG ( c, d, a, b, x[3], S23, 0xf4d50d87); /* 27 */ GG ( b, c, d, a, x[8], S24, 0x455a14ed); /* 28 */ GG ( a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ GG ( d, a, b, c, x[2], S22, 0xfcefa3f8); /* 30 */ GG ( c, d, a, b, x[7], S23, 0x676f02d9); /* 31 */ GG ( b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ /* Round 3 */ HH ( a, b, c, d, x[5], S31, 0xfffa3942); /* 33 */ HH ( d, a, b, c, x[8], S32, 0x8771f681); /* 34 */ HH ( c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ HH ( b, c, d, a, x[14], S34, 0xfdeS380c); /* 36 */ HH ( a, b, c, d, x[1], S31, 0xa4beea44); /* 37 */ HH ( d, a, b, c, x[4], S32, 0x4bdecfa9); /* 38 */ HH ( c, d, a, b, x[7], S33, 0xf6bb4b60); /* 39 */ HH ( b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ HH ( a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ HH ( d, a, b, c, x[0], S32, 0xeaa127fa); /* 42 */ HH ( c, d, a, b, x[3], S33, 0xd4ef3085); /* 43 */ HH ( b, c, d, a, x[6], S34, 0x4881d05); /* 44 */ HH ( a, b, c, d, x[9], S31, 0xd9d4d039); /* 45 */ HH ( d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ HH ( c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ HH ( b, c, d, a, x[2], S34, 0xc4ac5665); /* 48 */ /* Round 4 */ II ( a, b, c, d, x[()], S41, 0xf4292244); /* 49 */ II ( d, a, b, c, x[7], S42, 0x432aff97); /* 50 */ II ( c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ II ( b, c, d, a, x[5], S44, 0xfc93a039); /* 52 */ II ( a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ II ( d, a, b, c, x[3], S42, 0x8f0ccc92); /* 54 */ II ( c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ II ( b, c, d, a, x[1], S44, 0x85845dd1); /* 56 */ II ( a, b, c, d, x[8], S41, 0x6fa87e4f); /* 57 */ II ( d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ ti ( c, d, a, b, x[6], S43, 0xa3014314); /* 59 */ II ( b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ II ( a, b, c, d, x[4], S41, 0xf7537e82); /* 61 */ II ( d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ II ( c, d, a, b, x[2], S43, 0x2ad7d2bb); /* 63 */ II ( b, c, d, a, x[9], S44, 0xeb86d391); /* 64 */ state[0] += a; state[1] += b; state[2] += c; state[3] += d; /* Zeroize sensitive information. */ MD5.sub.-- memset ((POINTER)x, 0, sizeof (x)); } /* Encodes input (UINT4) into output (unsigned char). Assumes len is a multiple of 4. */ static void Encode (output, input, len) unsigned char *output; UINT4 *input; unsigned int len; { unsigned int i, j; for(i = 0, j = 0; j &lt; len; i++, j += 4) { output[j] = (unsigned char)(input[i] & 0xff); output[j+1] = (unsigned char)((input[i] &gt;&gt; 8) & 0xff); output[j+2] = (unsigned char)((input[i] &gt;&gt; 16) & 0xff); output[j+3] = (unsigned char)((input[i] &gt;&gt; 24) & 0xff); } } /* Decodes input (unsigned char) into output (UINT4). Assumes len is a multiple of 4. */ static void Decode (output, input, len) UINT4 *output; unsigned char *input; unsigned int len; { unsigned int i, j; for(i = 0, j = 0; j &lt; len; i++, j += 4) output[i] = ((UINT4)input[j]) .vertline. (((UINT4)input[j+1]) &lt;&lt; 8) .vertline. (((UINT4)input[j+2]) &lt;&lt; 16) .vertline. (((UINT4)input[j+3]) &lt;&lt; 24); } /* Note: Replace "for loop" with standard memcpy if possible. */ static void MD5.sub.-- memcpy (output, input, len) POINTER output; POINTER input; unsigned int len; { unsigned int i; for (i = 0; i &lt; len; i++) output[i] = input[i]; } /* Note: Replace "for loop" with standard memset if possible. */ static void MD5.sub.-- memset (output, value, len) POINTER output; int value; unsigned int len; { unsigned int i; for (i = 0; i &lt; len; i++) ((char *)output)[i] = (char)value; } ______________________________________
The RSA Data Security, Inc. MD5 Message-Digest Algorithm, when implemented in software as shown in Table 1 above, is executed by a processor. There are some applications, however, where it is desirable to implement the RSA Data Security, Inc. MD5 Message-Digest Algorithm without requiring that the algorithm be executed by a general purpose processor.